package com.youlu.campus.service.rank.impl;

import com.alibaba.fastjson.JSON;
import com.youlu.campus.activity.service.UserActivityTaskRankingService;

import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.ActivityTaskInfo;
import com.youlu.campus.entity.OrganizerRankingList;
import com.youlu.campus.entity.UniversityActivityTaskRanking;
import com.youlu.campus.service.ranking.entity.UserActivityTaskRanking;
import com.youlu.campus.entity.VO.req.ActivityRankFlushRequest;
import com.youlu.campus.entity.enums.TaskBizType;
import com.youlu.campus.service.activity.ActivityTaskService;
import com.youlu.campus.service.base.LockService;
import com.youlu.campus.service.rank.RankBaseService;
import com.youlu.campus.service.rank.RankService;
import com.youlu.campus.service.rank.UserRankListService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class RankServiceImpl implements RankService {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private MongoTemplate mongoTemplate;

    @Lazy
    @Autowired
    private ActivityTaskService activityTaskService;
    @Autowired
    private LockService lockService;
    @Autowired
    private RankBaseService rankBaseService;
    @Autowired
    private UserRankListService userRankListService;

    @Autowired
    private UserActivityTaskRankingService userActivityTaskRankingService;

    /**
     * 大学排行榜-缓存前缀
     */
    public static final String UNIVERSITY_RANK_LIST_PEFIX = "youlu:runtime:university-rank::activityId:%s::page:%d";

    /**
     * 承办单位排行榜-缓存前缀
     */
    public static final String ORG_RANK_LIST_PEFIX = "youlu:runtime:task-rank-:org::taskId:%s:province:%s:page:%d";

    static String[] provinces = {"北京市", "上海市", "天津市", "重庆市", "北京", "上海", "天津", "重庆", "河北省", "河北", "河北省", "河北", "山西省", "山西", "内蒙古自治区", "内蒙",
            "辽宁省", "辽宁", "吉林省", "吉林", "黑龙江省", "黑龙江", "江苏省", "江苏", "浙江省", "浙江", "安徽省", "安徽", "福建", "福建省", "江西省", "江西", "山东省", "山东", "河南省", "河南", "湖北省", "湖北",
            "湖南省", "湖南", "广东省", "广东", "广西壮族自治区", "广西", "海南省", "海南", "四川省", "四川", "贵州省", "贵州", "云南省", "云南", "西藏自治区", "西藏", "陕西省", "陕西", "甘肃省", "甘肃",
            "青海省", "青海", "宁夏回族自治区", "宁夏", "新疆维吾尔自治区", "新疆", "香港特别行政区", "香港", "澳门特别行政区", "澳门", "台湾省", "台湾"};

    @Override
    public void setOrganizerRankListCache(String taskId, String province, Integer page, List<OrganizerRankingList> datas) {
        log.info(":>>> 开始设置任务承办榜单列表缓存:{},{},{},{}", taskId, province, page, datas == null ? 0 : datas.size());
        String key = String.format(ORG_RANK_LIST_PEFIX, taskId, province, page);
        redisTemplate.opsForValue().set(key, JSON.toJSONString(datas), 5, TimeUnit.MINUTES);
        log.info(":>>> 设置任务承办榜单列表缓存:{},{},{},一个小时后过期", taskId, province, page);
    }

    @Override
    public List<UniversityActivityTaskRanking> getUniversityRankListCache(String activityId, Integer page) {
        log.info(":>>> 开始获取活动大学榜单列表缓存:{},{}", activityId, page);
        String key = String.format(UNIVERSITY_RANK_LIST_PEFIX, activityId, page);
        Object data = redisTemplate.opsForValue().get(key);
        if (Objects.isNull(data)) {
            log.error(":>>> activityId:{}:{},page:{} ,大学榜单数据不存在", activityId, page);
            return null;
        }
        List<UniversityActivityTaskRanking> datas = JSON.parseArray((String) data, UniversityActivityTaskRanking.class);
//        log.info(":>>> taskId:{},,page:{} ,大学榜单:{}", activityId, page, JSON.toJSONString(datas));
        return datas;
    }

    @Override
    public void setUniversityRankListCache(String activityId, Integer page, List<UniversityActivityTaskRanking> datas) {
        log.info(":>>> 开始设置大学榜单列表缓存:{},{},{}", activityId, page, JSON.toJSONString(datas));
        String key = String.format(UNIVERSITY_RANK_LIST_PEFIX, activityId, page);
        redisTemplate.opsForValue().set(key, JSON.toJSONString(datas), 1, TimeUnit.HOURS);
        log.info(":>>> 设置大学榜单列表缓存:{},{},{},一个小时后过期", activityId, page);
    }

    @Async
    @Override
    public void preSetRankDataCache(ActivityRankFlushRequest request) {
        if (request == null) {
            log.info("刷新排行榜参数为空");
            return;
        }
        List<String> aidList = request.getActivityIdList();
        if (CollectionUtils.isEmpty(aidList)) {
            log.info("刷新排行榜活动Id参数为空");
            return;
        }
        log.info(":>>> 开始预刷新排行榜,activityId list:{}", aidList);
//        Query query = new Query().addCriteria(Criteria.where("deleted").ne(Boolean.TRUE));
        Query query = new Query();
        query.addCriteria(Criteria.where("id").in(aidList));
        List<ActivityInfo> activityInfos = mongoTemplate.find(query, ActivityInfo.class);
        if (CollectionUtils.isEmpty(activityInfos)) {
            log.error(":>>> 活动信息为空");
            return;
        }
        log.info(":>>> 待刷新活动排行榜数据大小:{}", activityInfos == null ? 0 : activityInfos.size());
        for (ActivityInfo activityInfo : activityInfos) {
            log.info(":>>>  开始加载活动:{},{} 排行榜，活动类型:{}", activityInfo.getId(), activityInfo.getName(), activityInfo.getType());
            /**
             * 类型,before:之前活动类型,contest-plus:竞赛类,h5-plus:h5新版,
             * qq-mini-plus:小程序活动plus竞赛类
             * qq-mini-plus-noncontest:小程序活动plus非竞赛类
             */
            switch (activityInfo.getType()) {
                case "before":
                    flushBeforeActivityRank(activityInfo, request);
                    break;
//                case "h5-plus":
//                    flushH5PlusActivityRank(activityInfo, date);
//                    break;
//                case "qq-mini-plus-noncontest":
//                    flushH5PlusActivityRank(activityInfo, date);
//                    break;
//                case "qq-mini-plus":
//                    flushH5PlusActivityRank(activityInfo, date);
//                    break;
                default:
                    break;
            }


        }
    }


    @Override
    public String[] getAllProvinces() {
        return provinces;
    }

    @Override
    public void flushUserRankListToCanche(ActivityRankFlushRequest rankFlushRequest) {
        log.info(":>>> 开始刷新用户排行榜到缓存中");
        lockService.unLock("flushUserRankListToCanche");
        boolean lock = lockService.tryLock("flushUserRankListToCanche", 1, TimeUnit.HOURS);
        log.info(":>>> 获取用户排行榜缓存刷新锁结果:{}", lock);
        try {
            if (lock) {
                this.preSetRankDataCache(rankFlushRequest);
//                this.preSetProvinceRankDataCache(activityId);
            }
        } catch (Exception e) {
            log.error(":>>> 处理用户排行榜到缓存中失败:{}", e);
        } finally {
            if (lock) {
                lockService.unLock("flushUserRankListToCanche");
                log.info(":>>> 结束刷新用户排行榜到缓存中,释放锁:{}", "flushUserRankListToCanche");
            }

        }
    }

    /**
     * 刷新老活动全国排行榜
     *
     * @param activityInfo
     * @param request
     */
    private void flushBeforeActivityRank(ActivityInfo activityInfo, ActivityRankFlushRequest request) {
        log.info(":>>>  开始加载活动:{},{} 排行榜,老版本,请求参数", activityInfo.getId(), activityInfo.getName(), request);
        ActivityTaskInfo taskInfo = activityTaskService.find(activityInfo.getId(), TaskBizType.INVITE);
        if (Objects.isNull(taskInfo)) {
            log.error(":>>> 活动:{} 无配置的任务,请联系客服", activityInfo.getId());
            return;
        }
        Date start = new Date();
        Query queryR = new Query();
        queryR.addCriteria(Criteria.where("taskId").is(taskInfo.getId()).and("activityId").is(taskInfo.getActivityId()));
        if (!CollectionUtils.isEmpty(request.getUserIdList())) {
            queryR.addCriteria(Criteria.where("userId").in(request.getUserIdList()));
        }
        long total = 0;
        // 按照排行榜的大小排序清晰
        if (request.getSort()) {
            Sort sort = Sort.by(Sort.Direction.DESC, "quantity");
            queryR.with(sort);
        }
        // 使用自己传的总数
        if (request.getUseLimit()) {
            total = request.getTotal();
        } else {
            total = mongoTemplate.count(queryR, UserActivityTaskRanking.class);
        }
        if (total <= 0) {
            log.info("处理排行榜数据总条数{}条,结束", total);
            return;
        }
        int pageSize = request.getPageSize();
        // 设置省查询
        log.info("处理排行榜数据总条数:{},每页条数:{}", total, pageSize);
        int pages = (int) ((total + pageSize - 1) / pageSize);
        for (int page = 0; page < pages; page++) {
            List<UserActivityTaskRanking> datas = userActivityTaskRankingService.getListFromDb(queryR, activityInfo.getId(), page + 1, pageSize);
            log.info(":>>> 活动:{} 第:{} 页排行榜数据不存在,数据库中查询大小:{},耗时:{} 毫秒", activityInfo.getName(), 1000, datas == null ? 0 :
                    datas.size(), (System.currentTimeMillis() - start.getTime()));
            if (CollectionUtils.isEmpty(datas)) {
                return;
            }
            for (UserActivityTaskRanking userActivityTaskRanking : datas) {
                String key = userRankListService.getAllRankCountryKey(userActivityTaskRanking.getActivityId(), userActivityTaskRanking.getTaskId());
                rankBaseService.addSingleRank(key, userActivityTaskRanking.getUserId(), userActivityTaskRanking.getQuantity());

                if (org.apache.commons.lang3.StringUtils.isNotBlank(userActivityTaskRanking.getProvince())) {
                    //省榜再这里加没有问题的
                    String prokey = userRankListService.getAllRankProvinceKey(userActivityTaskRanking.getActivityId(), userActivityTaskRanking.getTaskId(), userActivityTaskRanking.getProvince());
                    rankBaseService.addSingleRank(prokey, userActivityTaskRanking.getUserId(), userActivityTaskRanking.getQuantity());
                }
            }
        }
        log.info("处理排行榜数据总条数:{},每页条数:{},结束", total, pageSize);
    }

}
